/*
 * nwprogserver.cpp
 *
 *  Created on: Mar 13, 2012
 *      Author: shaohong
 */


#include <assert.h>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>

#include "WebServer.h"
#include "Utils.h"

using namespace std;

static const char *optString = "+p:d:h?";

static struct ProgConfig {
	uint32_t server_port;	// the port that the server is going to bind and listen to

	string www_root;	// the root directory relative to which the resources are to be fetched/put

} serverConfig; // the program configuration


// print the program configuration
static void printProgConfig(ProgConfig config);

//parsing the command line options
static void parseCommandLine(int argc, char *argv[]);

// check if the given configuration is correct
static bool isConfigValid(ProgConfig serverConfig);

// the one and only webserver we're running
static WebServer * theWebServer;

/*
 *The SIG_TERM handler for the main process.
 */
static void sigTermHandler(int sigNo) {
	theWebServer->gracefulShutDown();
}



// main function
int main(int argc, char ** argv) {

	// parse the command line options
	parseCommandLine(argc, argv);

	Utils::daemonize();

    //set up the signal handler
    Utils::setupSigHandler(SIGTERM, sigTermHandler);

    // ignore SIG_PIPE so that we don't crash when client disconnects during reading GET response
    Utils::setupSigHandler(SIGPIPE, SIG_IGN);

	printProgConfig(serverConfig);

	theWebServer = new WebServer(serverConfig.server_port, serverConfig.www_root);

	theWebServer->run();

	return 0;

}

/*
 * Print the usage information to the user
 */
void printUsage(void) {
	cout
			<< "======\n"
			<< "usage:\n"
			<< "======\n"
			<< "	nwprogserver [options] "
			<< endl
			<< endl
			<< "Options:\n"
			<< "    -p port Specifies the port the server is listening to."
			<< endl
			<< endl
			<< "    -d www_root_directory Specifies the root directory of the www server."
			<< endl
			<< endl;
}


void parseCommandLine(int argc, char *argv[]) {

	// check the argument list

	// if argument list is empty, print the usage.
	if (1 == argc) {
		printUsage();

		exit(EXIT_FAILURE);
	}

	/* Process the arguments with getopt(), then
	 * populate streamerConfig.
	 */
	int opt = getopt(argc, argv, optString);
	while (opt != -1) {

		switch (opt) {
		case 'p': // the port this server is going to listen to
			if (NULL != optarg) {
				serverConfig.server_port  = atoi(optarg);
			} else {
				printUsage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'd': // path to local file
			if (NULL != optarg) {
				serverConfig.www_root = string(optarg);
			} else {
				printUsage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'h':
		case '?':
			printUsage();
			exit(EXIT_FAILURE);
			break;

		default:
			printUsage();

			exit(EXIT_FAILURE);
		}

		opt = getopt(argc, argv, optString);
	}

	//check if the provided options are correct
	if (!isConfigValid(serverConfig)) {
		printUsage();
		exit(EXIT_FAILURE);
	}
}

void printProgConfig(ProgConfig config) {
	cerr << "Program configurations: " << endl;
	cerr << "	listening port = " << config.server_port << endl;
	cerr << "	www_root = " << config.www_root << endl;
}

// check if the given server configuration is correct
bool isConfigValid(ProgConfig serverConfig)
{
	if (serverConfig.server_port <=0) {
		return false;
	}

	if (serverConfig.www_root.empty()) {
		return false;
	}

	return true;
}



